//
// SCP1000_GRAPH.pde
//
// Read pressure sensor data from Arduino via serial interface and draw chart.
// In current sketch, Arduino sends data every 15 minutes.
// format of data as follows
// "xxxx.xx hpa yy.yy C"
//
// written by elekid.
//
// Processing site : http://processing.org
//

import processing.serial.*;

Serial port;
PFont myFont;

int cnt=0;

static int DATASIZE = 300;
float[] data = new float[DATASIZE];
String[] tag = new String[DATASIZE];

static int chartX = 50;
static int chartY = 10;
static int chartWidth = 600;
static int chartHeight = 400;

static int chartBackground = 240;
static int chartBackgroundNight = 215;

color dataColor = color(24, 24,128 );
color msgColor = color(255,0,0);
color lineColor = color(128);

float maxdata;
float mindata;
int intMaxdata;
int intMindata;


// for future use
static int defaultMaxBaro=1010;
static int defaultMinBaro=999;

/**
 * setup()
 */
void setup(){
  myFont = createFont("SansSerif", 18);
  println(Serial.list());
  size (660,480);

  // Assuming that 3rd serial port is connected to Arduino
  port = new Serial(this, Serial.list()[2], 9600);

  // Data will be available when NL(LF) receive.
  // 
  port.bufferUntil(10);

  // draw() will be called every 5 seconds.
  // CPU使用率を下げるためフレームレートを1以下に設定
  frameRate(0.2);

  // FOR DEBUG
  /*
  addData("21:17", 1000.45);
  addData("21:32", 1000.41);
  addData("21:47", 1000.38);
  addData("22:02", 1000.28);
  */
  // [2010/6/22 22:02:47] 1000.28 hPa 27.90 C
}

/**
 * draw()
 */
void draw(){
  background(210);
  smooth();

  // draw graph area
  noStroke();
  fill(chartBackground);
  rect( chartX, chartY, chartWidth, chartHeight);

  // colorize graph area
  colorArea();

  // draw graph
  plotDataLabel();
  drawChart();

  // display current value
  textFont(myFont, 18);
  fill(msgColor);
  text ("now : ", 170 , chartY + 20 );
  textFont(myFont, 24);
  int hpa_disp=int((float)(data[0]*2)/2);
  text(hpa_disp, 215, chartY + 20);
  textFont(myFont, 18);
  text ("hPa", 275 , chartY + 20 );

}

/**
 * serialEvent()
 *
 * automatically called when Serial data is available.
 * シリアルからのデータ受信時に自動的に呼び出される。
 */
void serialEvent(Serial p) {

  String inString = (port.readString());
  saveLogFile(inString);
  String[] s=split(inString, " ");

  String msg=String.format("%02d", hour()) + ":" +String.format("%02d",minute());
  println(s[0] + " / " + msg);

  addData(msg, float(s[0]));

}

/**
 * addData()
 *
 * store sensor data into array
 * シリアルで受信したセンサーのデータを配列にセットする
 * 配列の要素数は有限なので、古いものから上書きされて行く
 * 最新は要素0に保管
 */
void addData(String msg, float hpa) {

  cnt++;
  if ( cnt > DATASIZE) {
    cnt = DATASIZE;
  }

  // store latest data into data[0],
  for ( int i=cnt-1 ; i > 0 ; i--){
    data[i]=data[i-1];
    tag[i] = tag[i-1];
  }
  data[0] =hpa;
  tag[0] = msg;

  maxdata = data[0] ;
  mindata = data[0] ;

  for ( int i = 1 ; i < cnt ; i++) {
    if ( data[i] > maxdata ){
      maxdata = data[i];
    }
    if (data[i] < mindata ){
      mindata = data[i];
    }
  }
  if ( int(mindata) < defaultMinBaro ) {
    intMindata = int(mindata);
  }
  else {
    intMindata = defaultMinBaro;
  }
  if ( int(maxdata) > defaultMaxBaro ) {
    intMaxdata = int (maxdata)+1;
  }
  else {
    intMaxdata = defaultMaxBaro;
  }


}


/**
 * drawChart()
 *
 * draw line chart
 * vertex()により折れ線グラフを描画する
 */
void drawChart(){
  stroke(dataColor);
  noFill();
  strokeWeight(2);

  beginShape();
  for (int i = 0 ; i <cnt ; i++){
    float x = getX(i);
    float y = getY(data[i]);
    vertex( x ,y );
    if ( i-1 == cnt || i == 0) {
      vertex( x ,y );
    }
  }
  endShape();

}

/**
 * plotDataLabel()
 *
 * plot x/y axis labels
 * x軸及びy軸の描画、データラベルも
 */
void plotDataLabel(){
  textFont(myFont,10);
  for ( int v = intMindata ; v <= intMaxdata ; v++) {
    noFill();
    strokeWeight(1);
    stroke(lineColor);
    line ( chartX , getY(v), chartX+chartWidth, getY(v));
    fill(dataColor);
    text(v,chartX-30,getY(v)+5);

  }

  for ( int v = 0 ; v < DATASIZE ; v += 4) {
    noFill();
    strokeWeight(1);
    stroke(lineColor);
    line ( getX(v) , getY(intMaxdata), getX(v), getY(intMindata));
  }

  for ( int v = 0 ; v < DATASIZE ; v+=8) {
    if ( v >= cnt ) break;
    pushMatrix();
    translate(getX(v),getY(intMindata)+30);
    rotate(PI*3/2);
    fill(dataColor);
    text(tag[v],0,0);
    popMatrix();

  }
}

/*
* getX()
 *
 * calc x value
 * 描画の際の基準となるx値を計算する
 */
float getX (int cnt){
  float x = chartX + chartWidth - (cnt * chartWidth / DATASIZE);
  return x;
}

/*
* getY()
 *
 * calc y value
 * 描画の際の基準となるy値を計算する。
 */
float getY(float val){
  float y = chartY + (1 + intMaxdata - val) * chartHeight / (intMaxdata -
    intMindata+2);
  return y;
}

/*
* saveLogFile()
 *
 * save sensor data into log file
 * シリアルで受信したデータにタイムスタンプを付与してログファイルに保存する
 * ファイルはスケッチの保存ディレクトリに作成される
 */
void saveLogFile(String outString) {
  String buffer = "[";
  buffer += String.valueOf(year());
  buffer += "/";
  buffer += String.valueOf(month());
  buffer += "/";
  buffer += String.valueOf(day());
  buffer += " ";
  buffer += String.format("%02d", hour());
  buffer += ":";
  buffer += String.format("%02d", minute());
  buffer += ":";
  buffer += String.format("%02d", second());
  buffer += "] ";
  buffer += outString;

  // open existing file
  // 初回実行時にはゼロバイトでファイルを作成しておく必要がある
  String[] lines = loadStrings("sensor_data.log");
  String[] newlines= append( lines, buffer);

  // add one line and save
  saveStrings("sensor_data.log", newlines);
  print(buffer);
}
/*
* colorArea()
 *
 * 日付の変わり目の視認性を向上させるため
 * グラフの中で深夜 0:00 前後のエリアの背景色を暗くする
 */
void colorArea(){
  int [] MidNight = {
    0   };
  int pos=0;
  boolean foundFlg = false ;
  boolean foundFlgPrev = false ;

  for ( int i = 0 ; i < cnt ; i++){
    String[] s=split(tag[i], ":");
    // 0:xx found
    if (int(s[0]) == 0 ) {
      foundFlg=true;
      if ( MidNight.length < pos + 1) {
        MidNight = append(MidNight, 0);
      }
      // println("pos=" + pos);
      // println(" i=" + i);
      MidNight[pos] = i ;
    }
    else {
      foundFlg=false;
    }
    if ( (foundFlg == false) && (foundFlgPrev == true) ) {
      pos++;
    }
    foundFlgPrev=foundFlg;
  }

  for ( int i = 0 ; i < MidNight.length ; i++ ){
    // datasize = 200
    // width= 400
    // --> 15 min = 2pixcel
    // --> 6 hour = 6 * 4 * 2= 48 pixcel
    // -->
    float mx = getX(MidNight[i]);
    if ( (mx -48 ) >= chartX && ( mx + 48 <= chartX + chartWidth )) {
      for (int j = 0 ; j < 96 ; j++ ){
        if ( j < 10 ) {
          stroke(chartBackground - j* 2 );
        }
        else if (j > 86 ) {
          stroke(chartBackground - (96-j)* 2 );
        }
        else {
          stroke (chartBackgroundNight);
        }
        // line( x, y, x, y2 );
        line (mx - 48 + j, getY(intMaxdata), mx - 48 + j ,
        getY(intMindata));
      }
    }
    else if ( (mx -48 ) >= chartX && ( mx <= chartX + chartWidth )) {
      //println ("mx = " + mx);
      //println ("chartX + chartWidth - mx=" + (chartX + chartWidth - mx));
      for (int j = 0 ; j <= (48+(chartX + chartWidth - mx)) ; j++ ){
        if ( j < 10 ) {
          stroke(chartBackground - j* 2 );
        }
        else {
          stroke (chartBackgroundNight);
        }
        // line( x, y, x, y2 );
        line (mx - 48 + j, getY(intMaxdata), mx - 48 + j , getY(intMindata));
      }
    }
    else if ( ( mx + 48 <= chartX + chartWidth ) && mx >= chartX) {
      // TODO
      for (int j=0 ; j <= (mx - chartX + 48) ; j++){
        float c = (mx - chartX + 48) - j;
        if ( c <= 10 ){
          stroke(chartBackground - c * 2 );
        }
        else {
          stroke (chartBackgroundNight);
        }
        line (chartX + j, getY(intMaxdata), chartX + j , getY(intMindata));
      }

    }

  }
}




